package com.kehutong.common.isp;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.TreeMap;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

import org.coraframework.http.HttpClient;
import org.coraframework.inject.Inject;
import org.coraframework.inject.Singleton;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.util.CallBack;
import org.coraframework.util.time.TimeUtil;

import com.kehutong.common.urlconfig.SmsUrlConfig;

@Singleton
public class TencentSms {

	static final Logger logger = LoggerFactory.getLogger(TencentSms.class);

	@Inject
    private SmsUrlConfig smsConfig;
	
	
    private final static Charset UTF8 = StandardCharsets.UTF_8;
    private final static String SECRET_ID = "AKIDylITWNIH3WkkX4Haw1pCQQAfwwualARX";
    private final static String SECRET_KEY = "ynMemdF7k66tSqmTuCfrlSrzNbVGMDo4";
    
    private final static String service = "sms";
    private final static String host = "sms.tencentcloudapi.com";
    private final static String algorithm = "TC3-HMAC-SHA256";

    private static byte[] hmac256(byte[] key, String msg) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
        mac.init(secretKeySpec);
        return mac.doFinal(msg.getBytes(UTF8));
    }

    private static String sha256Hex(String s) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] d = md.digest(s.getBytes(UTF8));
        return DatatypeConverter.printHexBinary(d).toLowerCase();
    }

    public static void main(String[] args) throws Exception {
        List<String> mobiles = Arrays.asList("8615527700773");
        List<String> randomCodes = Arrays.asList("测试", "3");
        System.out.println(new TencentSms().sendSms(mobiles, randomCodes));
    }
    
    public JSONObject sendSms(List<String> mobiles, List<String> randomCodes) throws Exception {
        String timestamp = TimeUtil.timeSec() + "";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 注意时区，否则容易出错
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
        String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));

        // ************* 步骤 1：拼接规范请求串 *************
        String httpRequestMethod = "POST";
        String canonicalUri = "/";
        String canonicalQueryString = "";
        String canonicalHeaders = "content-type:application/json\n" + "host:" + host + "\n";
        String signedHeaders = "content-type;host";

        String TemplateID = "613771";
        String sign = "深圳客户通科技";
        String sdkId = "1400374763";
        
        String payload = sendContent(mobiles, TemplateID, sign, randomCodes, sdkId);
        String hashedRequestPayload = sha256Hex(payload);
        String canonicalRequest = 
        		httpRequestMethod + '\n' + 
        		canonicalUri + "\n" + 
				canonicalQueryString + "\n" +
				canonicalHeaders + "\n" + 
				signedHeaders + "\n" + 
				hashedRequestPayload;

        // ************* 步骤 2：拼接待签名字符串 *************
        String credentialScope = date + "/" + service + "/" + "tc3_request";
        String hashedCanonicalRequest = sha256Hex(canonicalRequest);
        String stringToSign = algorithm + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;

        // ************* 步骤 3：计算签名 *************
        byte[] secretDate = hmac256(("TC3" + SECRET_KEY).getBytes(UTF8), date);
        byte[] secretService = hmac256(secretDate, service);
        byte[] secretSigning = hmac256(secretService, "tc3_request");
        String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();

        // ************* 步骤 4：拼接 Authorization *************
        String authorization = algorithm + " " + "Credential=" + SECRET_ID + "/" + credentialScope + ", "
                + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;

        CallBack<HttpClient> httpCallBack = http->{
            TreeMap<String, String> headers = new TreeMap<>();
            headers.put("Authorization", authorization);
            headers.put("Content-Type", "application/json");
            headers.put("Host", host);
            headers.put("X-TC-Action", "SendSms");
            headers.put("X-TC-RequestClient", "APIExplorer");
            headers.put("X-TC-Timestamp", timestamp);
            headers.put("X-TC-Version", "2019-07-11");
            headers.put("X-TC-Language", "zh-CN");
            headers.put("X-TC-Language", "zh-CN");
            http.setHeaders(headers);
            http.setBody(payload);
        };

        return smsConfig.post("", httpCallBack);

    }
    
    private static String sendContent(List<String> mobiles, String TemplateID, String sign, List<String> randomCodes, String sdkId) {
    	StringBuilder buf = new StringBuilder();
    	buf.append('{');
    	
    	buf.append('"').append("PhoneNumberSet").append('"').append(":[");
    	for (String mobile : mobiles) {
    		buf.append('"').append(mobile).append('"').append(",");
    	}
    	buf.deleteCharAt(buf.length() - 1);
    	buf.append("],");
    	
    	buf.append('"').append("TemplateID").append('"').append(":")
    	.append('"').append(TemplateID).append('"').append(",");
    	
    	buf.append('"').append("Sign").append('"').append(":")
    	.append('"').append(sign).append('"').append(",");
    	
    	buf.append('"').append("TemplateParamSet").append('"').append(":[");
    	for (String code : randomCodes) {
    		buf.append('"').append(code).append('"').append(",");
    	}
    	buf.deleteCharAt(buf.length() - 1);
    	buf.append("],");
    	
    	buf.append('"').append("SessionContext").append('"').append(":")
    	.append('"').append("{0}为您的验证码，请于{1}分钟内填写，如非本人操作，请忽略本短信。").append('"').append(",");
    	
    	buf.append('"').append("SmsSdkAppid").append('"').append(":")
    	.append('"').append(sdkId).append('"');
    	
    	buf.append('}');
    	return buf.toString();
    }
}